/**
 * Copyright (c) 2018-2025, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: trace system
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2025-07-19     JasonHu           Init
 */

#ifndef __XBOOK_COLLECTOR__
#define __XBOOK_COLLECTOR__

#include <nxos_mini.h>
#include <base/list.h>
#include <base/thread.h>
#include <base/fifo.h>
#include <base/waitqueue.h>
#include <base/ioqueue.h>
#include <base/spin.h>

#define NX_TRACE_NAME_LEN 32

#define NX_TRACE_MAGIC_BASE 0x12ace
#define NX_TRACE_SOURCE_MAGIC (NX_TRACE_MAGIC_BASE)
#define NX_TRACE_EVENNT_MAGIC (NX_TRACE_MAGIC_BASE + 1)
#define NX_TRACE_TRACER_MAGIC (NX_TRACE_MAGIC_BASE + 2)
/**
 * extern device struct
 */
typedef struct NX_Device NX_Device;

typedef struct NX_EventSource NX_EventSource;

/**
 * filter for trace event and source
 */
typedef enum NX_TraceFilter {
    NX_TRACE_FILTER_FIRST = 0,
    NX_TRACE_FILTER_VER = NX_TRACE_FILTER_FIRST,
    NX_TRACE_FILTER_LEVEL,
    NX_TRACE_FILTER_TASK,
    NX_TRACE_FILTER_KEY,
    NX_TRACE_FILTER_NR
} NX_TraceFilter;

#define NX_TRACE_FILTER_MASK_VER     (1U << NX_TRACE_FILTER_VER)
#define NX_TRACE_FILTER_MASK_LEVEL   (1U << NX_TRACE_FILTER_LEVEL)
#define NX_TRACE_FILTER_MASK_TASK    (1U << NX_TRACE_FILTER_TASK)
#define NX_TRACE_FILTER_MASK_KEY     (1U << NX_TRACE_FILTER_KEY)

/**
 * trace event
 */
struct NX_TraceEvent
{
    NX_List list;
    char name[NX_TRACE_NAME_LEN];
    NX_List sourceList;

    NX_Spin sourceLock;
    NX_Device *device;
    NX_Bool enable;
    NX_Fifo *fifo[NX_MULTI_CORES_NR];
    NX_Semaphore eventsSem;
    NX_U32 magic;

    NX_U32 filter;
    NX_U32 filterVal[NX_TRACE_FILTER_NR];
};
typedef struct NX_TraceEvent NX_TraceEvent;

#define NX_EVENT_RECORD_SIZE 128

#define NX_EVENT_RECORD_MAX_NR 32

/* trace event reprot header */
typedef struct NX_EventHeader
{
    NX_U32 id;
    NX_U16 version;
    NX_U8 level;
    NX_U8 optcode;
    NX_U32 task;
    NX_U32 keyword;
    NX_U64 time;
} NX_EventHeader;

#define NX_EVENT_HEADER_INIT(id, ver, level, opt, task, keyword) \
    {id, ver, level, opt, task, keyword, 0}

#define NX_EVENT_HEADER_DEFINE(name) \
    NX_EventHeader name = NX_EVENT_HEADER_INIT(0, 0, 0, 0, 0, 0)

#define NX_EVENT_RECORD_DATA_SIZE (NX_EVENT_RECORD_SIZE - sizeof(NX_EventHeader))

/* trace event reprot */
struct NX_EventRecord
{
    NX_EventHeader header;
    NX_U8 data[NX_EVENT_RECORD_DATA_SIZE];
};
typedef struct NX_EventRecord NX_EventRecord;

typedef void (*NX_TraceEventHandler)(NX_EventRecord *record); 

/* trace event source */
struct NX_EventSource
{
    NX_List list;
    char name[NX_TRACE_NAME_LEN];
    NX_TraceEvent *event;
    NX_Device *device;
    NX_Bool enable;
    NX_U32 filter;
    NX_U32 filterVal[NX_TRACE_FILTER_NR];
    NX_U32 magic;
};
typedef struct NX_EventSource NX_EventSource;

#define NX_EVENT_SOURCE_INIT(name) \
    {NX_LIST_HEAD_INIT(EventSource_##name), #name, NX_NULL, NX_False, 0, {0}, NX_TRACE_SOURCE_MAGIC}

#define NX_EVENT_SOURCE_DEFINE(name) \
    NX_EventSource EventSource_##name = NX_EVENT_SOURCE_INIT(name)

#define NX_EVENT_SOURCE_STATIC(name) (&EventSource_##name)

/**
 * trace event interface
 */
NX_TraceEvent *NX_TraceEventCreate(char *name, NX_Size eventCount);
NX_Error NX_TraceEventDestroy(NX_TraceEvent *event);
NX_TraceEvent *NX_TraceEventSearch(char *name);
NX_Error NX_TraceEventEnable(NX_TraceEvent *event);
NX_Error NX_TraceEventDisable(NX_TraceEvent *event);
NX_Error NX_TraceEventWrite(NX_EventSource *source, NX_EventHeader *header, NX_U8 *data, NX_Size len);

NX_INLINE NX_Bool NX_TraceEventDisabled(NX_TraceEvent *event)
{
    return !event->enable;
}

/**
 * trace event source
 */
NX_EventSource *NX_EventSourceCreate(char *name);
NX_Error NX_EventSourceRegister(NX_EventSource *source, char *traceName);
NX_Error NX_EventSourceUnregister(NX_EventSource *source);
NX_Error NX_EventSourceDestroy(NX_EventSource *source);
NX_Error NX_EventSourceEanble(NX_EventSource *source, NX_Bool enable);

NX_INLINE NX_Bool NX_EventSourceDisabled(NX_EventSource *source)
{
    return !source->enable;
}

NX_Error NX_TraceEventSetFilter(NX_TraceEvent *event, NX_TraceFilter filter, NX_U32 value);
NX_Error NX_TraceEventClearFilter(NX_TraceEvent *event, NX_TraceFilter filter);
NX_Error NX_TraceEventResetFilter(NX_TraceEvent *event);
NX_Error NX_EventSourceSetFilter(NX_EventSource *source, NX_TraceFilter filter, NX_U32 value);
NX_Error NX_EventSourceClearFilter(NX_EventSource *source, NX_TraceFilter filter);
NX_Error NX_EventSourceResetFilter(NX_EventSource *source);

#if defined(CONFIG_TRACE_EVENT)
NX_Error NX_TraceInit(void);
NX_Error NX_TraceExit(void);
#else
#define NX_TraceInit()
#define NX_TraceExit()
#endif

#endif /* __XBOOK_COLLECTOR__ */
